﻿using System;
using System.Globalization;
using System.Threading;
using OpenTap.Plugins.Interfaces.Common;
using OpenTap.Plugins.Interfaces.MultiModeInstrument;
using OpenTap.Plugins.Interfaces.SG;

namespace OpenTap.Plugins.Sg
{
    [Display("Rohde&Schwarz Smate driver", Group: "OpenTap.Plugins", Description: "Rohde & Schwarz Signal generator")]
    public class SgRohdeSchwarzSmate : ScpiInstrument, ISg
    {
        #region Settings

        [Display("Clock source external", "Set clock source external", null, 1)]
        public EState ClockState { get; set; }

        #endregion

        public SgRohdeSchwarzSmate()
        {
            Name = "SMATE";
        }

        /// <summary>
        ///     Open procedure for the instrument.
        /// </summary>
        public override void Open()
        {
            base.Open();
            SetReferenceClockSource(ClockState);
            IoTimeout = 20000;
        }

        /// <inheritdoc />
        public void SetFrequency(double freqInMHz)
        {
            if (freqInMHz <= 0) throw new ArgumentOutOfRangeException(nameof(freqInMHz));
            ScpiCommand("FREQ " + (freqInMHz * 1E6).ToString("#.000000", CultureInfo.InvariantCulture) + ";*WAI");
        }

        /// <inheritdoc />
        public decimal GetFixedFrequency()
        {
            Log.Warning("Not supported on R&S SMATE");

            return decimal.MinValue;
        }

        /// <inheritdoc />
        public decimal GetFrequency()
        {
            return ScpiQuery<decimal>("FREQ?;*WAI");
        }

        /// <inheritdoc />
        public void SetOutputLevel(double outputLevelInDbm)
        {
            ScpiCommand("SOUR:POW " + outputLevelInDbm.ToString("#.000", CultureInfo.InvariantCulture) + ";*WAI");
        }

        /// <inheritdoc />
        public double GetOutputLevel()
        {
            return ScpiQuery<double>("SOUR:POW?" + ";*WAI");
        }

        /// <inheritdoc />
        public void SetRfOutputState(EState outputState)
        {
            ScpiCommand("OUTP:STAT " + Scpi.Format("{0}", outputState) + ";*WAI");
        }

        /// <inheritdoc />
        public void SetModulationState(EState modulationState)
        {
            ScpiCommand("SOUR:MOD:ALL:STAT " + Scpi.Format("{0}", modulationState) + ";*WAI");
        }

        /// <inheritdoc />
        public void SetAlcState(EState state)
        {
            Log.Warning("Not supported on R&S SMATE");
        }

        /// <inheritdoc />
        public void SetWidebandIqModulatorState(EState modulatorState)
        {
            Log.Warning("Not supported on R&S SMATE");
        }

        /// <inheritdoc />
        public void SetReferenceOscillatorAutoState(EState oscillatorState)
        {
            Log.Warning("Not supported on R&S SMATE");
        }

        /// <inheritdoc />
        public void SetReferenceClock(double refFreqInMhz, EArbRefSource referenceSource)
        {
            ScpiCommand("ROSC:SOUR " + Scpi.Format("{0}", referenceSource) + ";*WAI");
            if (referenceSource == EArbRefSource.RefsourceExt)
                ScpiCommand("ROSC:EXT:FREQ " + refFreqInMhz * 1E6 + ";*WAI");
        }

        /// <inheritdoc />
        public void SetSelectArbFile(string fileFolderAndName, double awgSampleClockMhz)
        {
            Log.Warning("Not supported on R&S SMATE");
        }

        /// <inheritdoc />
        public uint GetPowerCondition()
        {
            Log.Warning("Not supported on R&S SMATE");

            return uint.MinValue;
        }

        /// <inheritdoc />
        public void SetTriggerPolarity(ETriggerPolarity polarity)
        {
            Log.Info("Sg:Set trigger polarity");
            if (ETriggerPolarity.PolarityNeg == polarity)
                ScpiCommand("INP:TRIG:BBAND:SLOP NEG;*WAI");
            else
                ScpiCommand("INP:TRIG:BBAND:SLOP POS;*WAI");
        }

        /// <inheritdoc />
        public void SetTriggerDelay(double delayMs)
        {
            if (delayMs <= 0)
                throw new ArgumentException("Trying to set trigger delay <= 0 !", "delayMs");
            Log.Info("Sg:Set trigger delay");
            ScpiCommand("BB:ARB:TRIG:DEL " + delayMs.ToString(CultureInfo.InvariantCulture) + ";*WAI");
        }

        /// <inheritdoc />
        public void SetArbTriggerSourceExt()
        {
            Log.Info("Sg:Set Arb trigger source to external");
            ScpiCommand("BB:ARB:TRIG:SOUR EXT;*WAI");
        }

        public void SetArbState(EState arbState)
        {
            Log.Info("Sg:Set Arb State " + arbState);
            ScpiCommand("SOUR:BB:ARB:STAT " + Scpi.Format("{0}", arbState));
        }

        /// <inheritdoc />
        public EopcStatus Opc()
        {
            var opcStatus = ScpiQuery("*OPC?");
            return opcStatus.Equals("1") ? EopcStatus.Complete : EopcStatus.Incomplete;
        }

        public void SetRuntimeScaling(double scale)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        ///     Set clock source to ext/int
        /// </summary>
        /// <param name="clockState">Clock state</param>
        private void SetReferenceClockSource(EState clockState)
        {
            ScpiCommand(EState.On == clockState ? "ROSC:SOUR EXT" : "ROSC:SOUR INT");
        }

        #region Implementation of IScpi

        public void Clear()
        {
            ScpiCommand("*CLS");
        }

        #endregion

        #region Implementation of IMultiModeInstrument

        public void SetInstrumentMode(EInstrumentMode instrumentMode)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}